import random
from enum import Enum
from collections import Counter
from itertools import combinations
import time


class Suit(Enum):
    HEARTS = '♥'
    DIAMONDS = '♦'
    CLUBS = '♣'
    SPADES = '♠'


class Rank(Enum):
    TWO = (2, '2')
    THREE = (3, '3')
    FOUR = (4, '4')
    FIVE = (5, '5')
    SIX = (6, '6')
    SEVEN = (7, '7')
    EIGHT = (8, '8')
    NINE = (9, '9')
    TEN = (10, '10')
    JACK = (11, 'J')
    QUEEN = (12, 'Q')
    KING = (13, 'K')
    ACE = (14, 'A')

    def __init__(self, rank_value, symbol):
        self.rank_value = rank_value
        self.symbol = symbol


class Card:
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __str__(self):
        return f"{self.rank.symbol}{self.suit.value}"

    def __repr__(self):
        return str(self)


class HandRank(Enum):
    HIGH_CARD = 1
    PAIR = 2
    TWO_PAIR = 3
    THREE_OF_A_KIND = 4
    STRAIGHT = 5
    FLUSH = 6
    FULL_HOUSE = 7
    FOUR_OF_A_KIND = 8
    STRAIGHT_FLUSH = 9
    ROYAL_FLUSH = 10


class Player:
    def __init__(self, name, chips=1000, is_ai=True):
        self.name = name
        self.chips = chips
        self.hand = []
        self.is_ai = is_ai
        self.folded = False
        self.current_bet = 0
        self.all_in = False
        # 新增：记录玩家在每一轮的行动历史
        self.action_history = []
        self.vpip_hands = 0  # Voluntarily Put money In Pot
        self.pfr_hands = 0  # Pre-Flop Raise
        self.total_hands_played = 0
        self.showdown_wins = 0
        self.showdown_losses = 0

    def reset_for_new_round(self):
        self.hand = []
        self.folded = False
        self.current_bet = 0
        self.all_in = False
        self.action_history = []


class TexasHoldem:
    def __init__(self):
        self.deck = []
        self.community_cards = []
        self.pot = 0
        self.current_bet = 0
        self.small_blind = 10
        self.big_blind = 20
        self.dealer_position = 0
        self.min_raise_amount = 0  # 追踪最小加注额
        self.verbose_mode = False  # 控制输出详细度

        # 创建玩家：1个真人 + 5个强化AI
        self.players = [
            Player("你", 1000, is_ai=False),
            Player("玩家1", 1000, is_ai=True),  # 实际是 Shark - 鲨鱼
            Player("玩家2", 1000, is_ai=True),  # 实际是 Psycho - 疯子
            Player("玩家3", 1000, is_ai=True),  # 实际是 Robot - 机器人
            Player("玩家4", 1000, is_ai=True),  # 实际是 Trap - 陷阱大师
            Player("玩家5", 1000, is_ai=True)  # 实际是 Adapt - 适应者
        ]

        # 强化的AI风格参数 - 内部使用原名映射
        self.ai_styles = {
            "玩家1": {  # Shark
                "tightness": 0.65,
                "aggression": 0.85,
                "bluff_rate": 0.30,
                "3bet_rate": 0.12,
                "check_raise_rate": 0.15,
                "float_rate": 0.25,
                "squeeze_rate": 0.08
            },
            "玩家2": {  # Psycho
                "tightness": 0.35,
                "aggression": 0.95,
                "bluff_rate": 0.45,
                "3bet_rate": 0.20,
                "check_raise_rate": 0.25,
                "float_rate": 0.35,
                "squeeze_rate": 0.15
            },
            "玩家3": {  # Robot
                "tightness": 0.60,
                "aggression": 0.60,
                "bluff_rate": 0.33,  # GTO约33%诈唬频率
                "3bet_rate": 0.10,
                "check_raise_rate": 0.12,
                "float_rate": 0.20,
                "squeeze_rate": 0.06
            },
            "玩家4": {  # Trap
                "tightness": 0.70,
                "aggression": 0.40,
                "bluff_rate": 0.15,
                "3bet_rate": 0.06,
                "check_raise_rate": 0.20,  # 高过牌加注率
                "float_rate": 0.15,
                "squeeze_rate": 0.04,
                "slowplay_rate": 0.35  # 慢打强牌
            },
            "玩家5": {  # Adapt
                "tightness": 0.55,
                "aggression": 0.65,
                "bluff_rate": 0.25,
                "3bet_rate": 0.10,
                "check_raise_rate": 0.15,
                "float_rate": 0.25,
                "squeeze_rate": 0.08,
                "adaptation_rate": 0.8  # 策略适应速度
            }
        }

        self.active_players = []

        # 增强的玩家历史追踪
        self.player_stats = {}
        for player in self.players:
            self.player_stats[player.name] = {
                "total_hands": 0,
                "vpip": 0,  # Voluntarily Put money In Pot
                "pfr": 0,  # Pre-Flop Raise
                "af": 0,  # Aggression Factor
                "wtsd": 0,  # Went To ShowDown
                "w$sd": 0,  # Won money at ShowDown
                "fold_to_3bet": 0,
                "fold_to_cbet": 0,
                "check_raise": 0,
                "donk_bet": 0,
                "river_bluff_rate": 0,
                "recent_aggression": []  # 最近10手的激进度
            }

        # 公共牌面纹理分析
        self.board_texture = {
            "wetness": 0,  # 湿润度（听牌可能性）
            "paired": False,
            "flush_possible": False,
            "straight_possible": False,
            "high_card_board": False
        }

    def create_deck(self):
        """创建一副新牌"""
        self.deck = []
        for suit in Suit:
            for rank in Rank:
                self.deck.append(Card(rank, suit))
        random.shuffle(self.deck)

    def deal_cards(self):
        """发牌：每人2张底牌"""
        for player in self.players:
            if player.chips > 0:
                player.hand = [self.deck.pop(), self.deck.pop()]
                player.total_hands_played += 1

    def deal_community_cards(self, num):
        """发公共牌"""
        for _ in range(num):
            self.community_cards.append(self.deck.pop())
        # 分析牌面纹理
        self.analyze_board_texture()

    def analyze_board_texture(self):
        """分析公共牌面纹理"""
        if not self.community_cards:
            return

        ranks = [c.rank.rank_value for c in self.community_cards]
        suits = [c.suit for c in self.community_cards]

        # 检查是否有对子
        self.board_texture["paired"] = len(ranks) != len(set(ranks))

        # 检查同花可能性
        suit_counts = Counter(suits)
        self.board_texture["flush_possible"] = any(count >= 3 for count in suit_counts.values())

        # 检查顺子可能性
        sorted_ranks = sorted(set(ranks))
        self.board_texture["straight_possible"] = False
        for i in range(len(sorted_ranks) - 2):
            if sorted_ranks[i + 2] - sorted_ranks[i] <= 4:
                self.board_texture["straight_possible"] = True
                break

        # 检查高牌面
        self.board_texture["high_card_board"] = max(ranks) >= 11

        # 计算湿润度
        wetness = 0
        if self.board_texture["flush_possible"]:
            wetness += 0.3
        if self.board_texture["straight_possible"]:
            wetness += 0.3
        if self.board_texture["paired"]:
            wetness += 0.2
        if not self.board_texture["high_card_board"]:
            wetness += 0.2
        self.board_texture["wetness"] = wetness

    def evaluate_hand(self, cards):
        """评估牌型"""
        if len(cards) < 5:
            return (HandRank.HIGH_CARD, [])

        # 获取所有可能的5张牌组合
        all_combinations = list(combinations(cards, 5))
        best_hand = None
        best_rank = HandRank.HIGH_CARD
        best_values = []

        for combo in all_combinations:
            rank, values = self._evaluate_five_cards(list(combo))
            if rank.value > best_rank.value:
                best_rank = rank
                best_values = values
                best_hand = combo
            elif rank.value == best_rank.value:
                if values > best_values:
                    best_values = values
                    best_hand = combo

        return (best_rank, best_values)

    def _evaluate_five_cards(self, five_cards):
        """评估5张牌的牌型"""
        ranks = sorted([card.rank.rank_value for card in five_cards], reverse=True)
        suits = [card.suit for card in five_cards]

        rank_counts = Counter(ranks)
        is_flush = len(set(suits)) == 1
        is_straight = self._is_straight(ranks)

        # 检查各种牌型
        if is_straight and is_flush:
            if ranks == [14, 13, 12, 11, 10]:
                return (HandRank.ROYAL_FLUSH, ranks)
            return (HandRank.STRAIGHT_FLUSH, ranks)

        counts = sorted(rank_counts.values(), reverse=True)
        if counts == [4, 1]:
            return (HandRank.FOUR_OF_A_KIND, self._get_ranked_values(rank_counts, [4, 1]))

        if counts == [3, 2]:
            return (HandRank.FULL_HOUSE, self._get_ranked_values(rank_counts, [3, 2]))

        if is_flush:
            return (HandRank.FLUSH, ranks)

        if is_straight:
            return (HandRank.STRAIGHT, ranks)

        if counts == [3, 1, 1]:
            return (HandRank.THREE_OF_A_KIND, self._get_ranked_values(rank_counts, [3, 1, 1]))

        if counts == [2, 2, 1]:
            return (HandRank.TWO_PAIR, self._get_ranked_values(rank_counts, [2, 2, 1]))

        if counts == [2, 1, 1, 1]:
            return (HandRank.PAIR, self._get_ranked_values(rank_counts, [2, 1, 1, 1]))

        return (HandRank.HIGH_CARD, ranks)

    def _is_straight(self, ranks):
        """检查是否是顺子"""
        # 检查普通顺子
        for i in range(len(ranks) - 1):
            if ranks[i] - ranks[i + 1] != 1:
                break
        else:
            return True

        # 检查A-2-3-4-5的特殊顺子
        if sorted(ranks) == [2, 3, 4, 5, 14]:
            return True

        return False

    def _get_ranked_values(self, rank_counts, pattern):
        """根据牌型模式获取排序后的牌值"""
        values = []
        for count in pattern:
            for rank, c in sorted(rank_counts.items(), reverse=True):
                if c == count and rank not in values:
                    values.append(rank)
                    break
        return values

    def betting_round(self, round_name):
        """进行一轮下注"""
        print(f"\n=== {round_name} ===")
        self.active_players = [p for p in self.players if not p.folded and p.chips > 0]

        if len(self.active_players) <= 1:
            return

        # 重置最小加注额
        self.min_raise_amount = self.big_blind

        # 确定起始位置
        if round_name == "翻牌前":
            # 翻牌前从大盲注后一位开始
            start_position = (self.dealer_position + 3) % len(self.players)
        else:
            # 其他轮从小盲注开始
            start_position = (self.dealer_position + 1) % len(self.players)
            while self.players[start_position].folded or self.players[start_position].chips == 0:
                start_position = (start_position + 1) % len(self.players)

        # 跟踪最后一个加注/下注的玩家
        last_aggressor = None
        players_acted = set()
        action_closed = False

        # 持续下注直到所有玩家都行动过且下注相同
        while not action_closed:
            action_closed = True

            for i in range(len(self.players)):
                player_index = (start_position + i) % len(self.players)
                player = self.players[player_index]

                # 跳过已弃牌、全下或没筹码的玩家
                if player.folded or player.all_in or player.chips == 0:
                    continue

                # 检查是否需要行动
                if player.current_bet < self.current_bet or player not in players_acted:
                    action_closed = False

                    # 玩家行动
                    if not player.is_ai:
                        action = self.human_action(player)
                    else:
                        action = self.enhanced_ai_action(player, round_name, last_aggressor)

                    # 确保action不是None
                    if action is None:
                        # 默认动作：如果可以过牌就过牌，否则弃牌
                        if player.current_bet < self.current_bet:
                            player.folded = True
                            self.print_ai_action(player.name, 'fold')
                            action = ('fold',)
                        else:
                            self.print_ai_action(player.name, 'check')
                            action = ('check',)

                    players_acted.add(player)

                    # 记录行动历史
                    player.action_history.append((round_name, action))

                    if action[0] in ['raise', 'bet']:
                        last_aggressor = player
                        # 更新最小加注额
                        if action[0] == 'raise':
                            self.min_raise_amount = action[1] - self.current_bet
                        players_acted = {player}
                        action_closed = False

        # 重置当前轮的下注
        for player in self.players:
            player.current_bet = 0
        self.current_bet = 0

    def human_action(self, player):
        """人类玩家行动"""
        print(f"\n你的手牌: {player.hand}")
        print(f"公共牌: {self.community_cards}")
        print(f"你的筹码: {player.chips}")
        print(f"底池: {self.pot}")
        print(f"当前下注: {self.current_bet}")
        print(f"你已下注: {player.current_bet}")

        to_call = self.current_bet - player.current_bet

        while True:
            if to_call == 0:
                print("\n选择行动: 1.过牌(Check) 2.下注(Bet) 3.弃牌(Fold)")
                choice = input("请选择 (1/2/3): ")

                if choice == '1':
                    print("你选择过牌")
                    return ('check',)
                elif choice == '2':
                    bet_amount = self.get_bet_amount(player, "下注", minimum=self.big_blind)
                    if bet_amount > 0:
                        self.make_bet(player, bet_amount)
                        return ('bet', bet_amount)
                elif choice == '3':
                    player.folded = True
                    print("你选择弃牌")
                    return ('fold',)
            else:
                print(f"\n需要跟注: {to_call}")
                print("选择行动: 1.跟注(Call) 2.加注(Raise) 3.弃牌(Fold)")
                choice = input("请选择 (1/2/3): ")

                if choice == '1':
                    call_amount = min(to_call, player.chips)
                    self.make_bet(player, player.current_bet + call_amount)
                    print(f"你跟注 {call_amount}")
                    return ('call',)
                elif choice == '2':
                    # 计算最小加注额
                    min_raise_total = self.current_bet + self.min_raise_amount
                    raise_amount = self.get_bet_amount(player, "加注", minimum=min_raise_total)
                    if raise_amount > 0:
                        self.make_bet(player, raise_amount)
                        return ('raise', raise_amount)
                elif choice == '3':
                    player.folded = True
                    print("你选择弃牌")
                    return ('fold',)

    def get_bet_amount(self, player, action_name, minimum=None):
        """获取下注金额"""
        if minimum is None:
            minimum = self.big_blind

        max_bet = player.chips + player.current_bet

        # 显示更清晰的提示
        if action_name == "加注":
            print(f"当前下注: {self.current_bet}")
            print(f"最小加注到: {minimum} (加注 {minimum - self.current_bet})")

        while True:
            try:
                if action_name == "加注":
                    amount = int(input(f"加注到多少 (最小: {minimum}, 最大: {max_bet}, 0取消): "))
                else:
                    amount = int(input(f"{action_name}金额 (最小: {minimum}, 最大: {max_bet}, 0取消): "))

                if amount == 0:
                    return 0
                if minimum <= amount <= max_bet:
                    return amount
                else:
                    print(f"金额必须在 {minimum} 到 {max_bet} 之间")
            except ValueError:
                print("请输入有效的数字")

    def print_ai_action(self, player_name, action, amount=None):
        """简洁的AI行动输出"""
        # 提取玩家编号
        player_num = player_name.replace("玩家", "") if "玩家" in player_name else ""

        if action == 'fold':
            print(f"{player_num}弃牌" if player_num else "弃牌")
        elif action == 'check':
            print(f"{player_num}过牌" if player_num else "过牌")
        elif action == 'call':
            print(f"{player_num}跟注" if player_num else "跟注")
        elif action == 'bet' and amount:
            print(f"{player_num}下注 {amount}" if player_num else f"下注 {amount}")
        elif action == 'raise' and amount:
            print(f"{player_num}加注 {amount}" if player_num else f"加注 {amount}")
        elif action == 'allin':
            print(f"{player_num}全下！" if player_num else "全下！")

    def enhanced_ai_action(self, player, round_name, last_aggressor):
        """增强版AI行动逻辑"""
        style = self.ai_styles.get(player.name)

        # 计算各种高级因素
        hand_strength = self.evaluate_ai_hand_strength(player)
        position = self.get_player_position(player)
        pot_size = self.pot
        to_call = self.current_bet - player.current_bet
        pot_odds = to_call / (self.pot + to_call) if to_call > 0 else 0
        stack_to_pot_ratio = player.chips / self.pot if self.pot > 0 else float('inf')

        # 获取对手统计信息
        opponent_stats = self.analyze_opponents(player)

        # 特殊AI行为
        if player.name == "玩家1":  # Shark
            return self.shark_ai_logic(player, hand_strength, position, pot_odds, round_name, opponent_stats)
        elif player.name == "玩家2":  # Psycho
            return self.psycho_ai_logic(player, hand_strength, position, pot_odds, round_name)
        elif player.name == "玩家3":  # Robot
            return self.gto_ai_logic(player, hand_strength, position, pot_odds, round_name)
        elif player.name == "玩家4":  # Trap
            return self.trap_ai_logic(player, hand_strength, position, pot_odds, round_name, last_aggressor)
        elif player.name == "玩家5":  # Adapt
            return self.adaptive_ai_logic(player, hand_strength, position, pot_odds, round_name, opponent_stats)

        # 默认动作（不应该到达这里）
        if to_call == 0:
            self.print_ai_action(player.name, 'check')
            return ('check',)
        else:
            player.folded = True
            self.print_ai_action(player.name, 'fold')
            return ('fold',)

    def shark_ai_logic(self, player, hand_strength, position, pot_odds, round_name, opponent_stats):
        """鲨鱼AI - 极度激进的专业玩家"""
        style = self.ai_styles["玩家1"]
        to_call = self.current_bet - player.current_bet

        # 位置加权
        position_bonus = position * 0.15
        adjusted_strength = hand_strength + position_bonus

        # 翻牌前策略
        if round_name == "翻牌前":
            # 扩大3bet范围
            if to_call > 0 and self.current_bet > self.big_blind:
                if adjusted_strength > 0.65 or (position > 0.7 and random.random() < style["3bet_rate"]):
                    # 3bet
                    raise_size = self.current_bet * random.uniform(2.5, 3.5)
                    total_bet = int(min(raise_size, player.chips + player.current_bet))
                    if total_bet > self.current_bet:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)

            # 偷盲策略
            elif position > 0.7 and adjusted_strength > 0.35:
                steal_size = random.uniform(2.2, 2.8) * self.big_blind
                bet_amount = int(min(steal_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)

        # 翻牌后策略
        else:
            # 持续下注
            if to_call == 0 and player in self.get_preflop_aggressors():
                # 高频C-bet
                if random.random() < 0.75:
                    cbet_size = self.pot * random.uniform(0.5, 0.75)
                    bet_amount = int(min(cbet_size, player.chips))
                    if bet_amount > 0:
                        self.make_bet(player, bet_amount)
                        self.print_ai_action(player.name, 'bet', bet_amount)
                        return ('bet', bet_amount)

            # 面对下注的激进打法
            elif to_call > 0:
                # 计算加注频率
                raise_frequency = style["aggression"] * (0.7 + adjusted_strength)

                if random.random() < raise_frequency and adjusted_strength > 0.45:
                    # 激进加注
                    raise_size = self.current_bet * random.uniform(2.2, 3.0)
                    total_bet = int(min(raise_size, player.chips + player.current_bet))
                    if total_bet > self.current_bet + self.min_raise_amount:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)

                # 宽松跟注范围
                elif adjusted_strength > 0.3 or pot_odds < 0.25:
                    call_amount = min(to_call, player.chips)
                    self.make_bet(player, player.current_bet + call_amount)
                    self.print_ai_action(player.name, 'call')
                    return ('call',)

        # 默认过牌/弃牌
        if to_call == 0:
            self.print_ai_action(player.name, 'check')
            return ('check',)
        else:
            player.folded = True
            self.print_ai_action(player.name, 'fold')
            return ('fold',)

    def psycho_ai_logic(self, player, hand_strength, position, pot_odds, round_name):
        """疯子AI - 极度不可预测"""
        style = self.ai_styles["玩家2"]
        to_call = self.current_bet - player.current_bet

        # 随机性因子
        chaos_factor = random.uniform(0.7, 1.3)
        adjusted_strength = hand_strength * chaos_factor

        # 疯狂行为触发
        go_crazy = random.random() < 0.25

        if go_crazy:
            # 25%概率做出疯狂举动
            if to_call == 0:
                # 超大下注
                crazy_bet = self.pot * random.uniform(1.5, 3.0)
                bet_amount = int(min(crazy_bet, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
            else:
                # 疯狂加注或跟注
                if random.random() < 0.6:
                    crazy_raise = self.current_bet * random.uniform(3, 5)
                    total_bet = int(min(crazy_raise, player.chips + player.current_bet))
                    if total_bet > self.current_bet + self.min_raise_amount:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)

        # 正常的激进打法
        if to_call == 0:
            if adjusted_strength > 0.25 or random.random() < style["bluff_rate"]:
                bet_size = self.pot * random.uniform(0.6, 1.2)
                bet_amount = int(min(bet_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
        else:
            # 宽松的跟注/加注范围
            if adjusted_strength > 0.2 or random.random() < 0.3:
                if random.random() < style["aggression"] * 0.4:
                    # 加注
                    raise_size = self.current_bet * random.uniform(2, 3.5)
                    total_bet = int(min(raise_size, player.chips + player.current_bet))
                    if total_bet > self.current_bet + self.min_raise_amount:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)
                else:
                    # 跟注
                    call_amount = min(to_call, player.chips)
                    self.make_bet(player, player.current_bet + call_amount)
                    self.print_ai_action(player.name, 'call')
                    return ('call',)

        # 默认行动
        if to_call == 0:
            self.print_ai_action(player.name, 'check')
            return ('check',)
        else:
            player.folded = True
            self.print_ai_action(player.name, 'fold')
            return ('fold',)

    def gto_ai_logic(self, player, hand_strength, position, pot_odds, round_name):
        """GTO AI - 博弈论最优策略"""
        style = self.ai_styles["玩家3"]
        to_call = self.current_bet - player.current_bet

        # GTO频率计算
        value_bet_threshold = 0.66  # 价值下注阈值
        bluff_frequency = 0.33  # 标准诈唬频率

        # 计算最优下注尺度
        if to_call == 0:
            # 两极化下注策略
            if hand_strength > value_bet_threshold:
                # 价值下注
                bet_size = self.calculate_gto_bet_size(True)
                bet_amount = int(min(bet_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
            elif hand_strength < 0.3 and random.random() < bluff_frequency:
                # 诈唬
                bet_size = self.calculate_gto_bet_size(False)
                bet_amount = int(min(bet_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
            else:
                self.print_ai_action(player.name, 'check')
                return ('check',)
        else:
            # 面对下注的GTO防守频率
            defend_frequency = 1 - (to_call / (self.pot + to_call))

            # 根据牌力和防守频率决定行动
            if hand_strength > 0.75:
                # 强牌加注
                if random.random() < 0.5:
                    gto_raise = self.current_bet * 2.5
                    total_bet = int(min(gto_raise, player.chips + player.current_bet))
                    if total_bet > self.current_bet + self.min_raise_amount:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)

            if hand_strength > (1 - defend_frequency):
                # 防守
                call_amount = min(to_call, player.chips)
                self.make_bet(player, player.current_bet + call_amount)
                self.print_ai_action(player.name, 'call')
                return ('call',)
            else:
                # 弃牌
                player.folded = True
                self.print_ai_action(player.name, 'fold')
                return ('fold',)

    def calculate_gto_bet_size(self, is_value):
        """计算GTO下注尺度"""
        # 基于底池的几何增长
        if len(self.community_cards) <= 3:  # 翻牌
            return self.pot * random.uniform(0.5, 0.75)
        elif len(self.community_cards) == 4:  # 转牌
            return self.pot * random.uniform(0.75, 1.0)
        else:  # 河牌
            if is_value:
                return self.pot * random.uniform(0.75, 1.5)
            else:
                return self.pot * random.uniform(0.5, 0.75)

    def trap_ai_logic(self, player, hand_strength, position, pot_odds, round_name, last_aggressor):
        """陷阱大师AI - 慢打和过牌加注"""
        style = self.ai_styles["玩家4"]
        to_call = self.current_bet - player.current_bet

        # 检查是否应该设置陷阱
        should_trap = (hand_strength > 0.75 and
                       random.random() < style.get("slowplay_rate", 0.35))

        if should_trap and to_call == 0:
            # 慢打强牌
            self.print_ai_action(player.name, 'check')
            return ('check',)

        # 过牌加注策略
        if (to_call > 0 and
                last_aggressor and
                hand_strength > 0.6 and
                random.random() < style["check_raise_rate"]):
            # 过牌加注
            trap_raise = self.current_bet * random.uniform(2.5, 3.5)
            total_bet = int(min(trap_raise, player.chips + player.current_bet))
            if total_bet > self.current_bet + self.min_raise_amount:
                self.make_bet(player, total_bet)
                self.print_ai_action(player.name, 'raise', total_bet)
                return ('raise', total_bet)

        # 正常打法
        if to_call == 0:
            if hand_strength > 0.55:
                # 价值下注
                bet_size = self.pot * random.uniform(0.4, 0.6)
                bet_amount = int(min(bet_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
            else:
                self.print_ai_action(player.name, 'check')
                return ('check',)
        else:
            # 紧的跟注范围
            if hand_strength > 0.5 or pot_odds < 0.2:
                call_amount = min(to_call, player.chips)
                self.make_bet(player, player.current_bet + call_amount)
                self.print_ai_action(player.name, 'call')
                return ('call',)
            else:
                player.folded = True
                self.print_ai_action(player.name, 'fold')
                return ('fold',)

    def adaptive_ai_logic(self, player, hand_strength, position, pot_odds, round_name, opponent_stats):
        """适应性AI - 根据对手调整策略"""
        style = self.ai_styles["玩家5"]
        to_call = self.current_bet - player.current_bet

        # 分析主要对手（人类玩家）
        human_stats = self.player_stats["你"]

        # 根据对手风格调整
        if human_stats["total_hands"] > 5:
            # 计算对手的激进度
            recent_aggression = sum(human_stats.get("recent_aggression", [])) / max(1, len(human_stats.get(
                "recent_aggression", [1])))

            # 动态调整策略
            if recent_aggression > 0.6:
                # 对手激进，收紧范围，增加陷阱
                adjusted_tightness = style["tightness"] * 1.2
                trap_frequency = 0.25
            else:
                # 对手被动，扩大诈唬
                adjusted_tightness = style["tightness"] * 0.8
                trap_frequency = 0.1
        else:
            adjusted_tightness = style["tightness"]
            trap_frequency = 0.15

        # 调整后的牌力要求
        adjusted_strength = hand_strength * (2 - adjusted_tightness)

        # 根据牌面纹理调整
        texture_adjustment = self.get_texture_adjustment()
        adjusted_strength *= texture_adjustment

        # 决策逻辑
        if to_call == 0:
            if adjusted_strength > 0.5 or (self.board_texture["wetness"] < 0.3 and random.random() < 0.3):
                # 下注
                bet_size = self.adaptive_bet_sizing(hand_strength)
                bet_amount = int(min(bet_size, player.chips))
                if bet_amount > 0:
                    self.make_bet(player, bet_amount)
                    self.print_ai_action(player.name, 'bet', bet_amount)
                    return ('bet', bet_amount)
            else:
                self.print_ai_action(player.name, 'check')
                return ('check',)
        else:
            # 根据对手倾向决定
            if adjusted_strength > 0.4 or (pot_odds < 0.3 and random.random() < trap_frequency):
                if random.random() < style["aggression"] * 0.5:
                    # 加注
                    raise_size = self.current_bet * random.uniform(2.2, 3.0)
                    total_bet = int(min(raise_size, player.chips + player.current_bet))
                    if total_bet > self.current_bet + self.min_raise_amount:
                        self.make_bet(player, total_bet)
                        self.print_ai_action(player.name, 'raise', total_bet)
                        return ('raise', total_bet)
                else:
                    # 跟注
                    call_amount = min(to_call, player.chips)
                    self.make_bet(player, player.current_bet + call_amount)
                    self.print_ai_action(player.name, 'call')
                    return ('call',)
            else:
                player.folded = True
                self.print_ai_action(player.name, 'fold')
                return ('fold',)

    def adaptive_bet_sizing(self, hand_strength):
        """适应性下注尺度"""
        # 根据对手历史和牌面决定下注大小
        if self.board_texture["wetness"] > 0.6:
            # 湿润牌面，大额下注保护
            return self.pot * random.uniform(0.75, 1.0)
        elif hand_strength > 0.8:
            # 超强牌，设置陷阱
            return self.pot * random.uniform(0.3, 0.5)
        else:
            # 标准下注
            return self.pot * random.uniform(0.5, 0.67)

    def get_texture_adjustment(self):
        """根据牌面纹理调整策略"""
        if not self.community_cards:
            return 1.0

        adjustment = 1.0
        if self.board_texture["flush_possible"]:
            adjustment *= 0.9
        if self.board_texture["straight_possible"]:
            adjustment *= 0.9
        if self.board_texture["paired"]:
            adjustment *= 0.95
        if self.board_texture["high_card_board"]:
            adjustment *= 1.05

        return adjustment

    def analyze_opponents(self, player):
        """分析对手数据"""
        opponent_stats = {}
        for p in self.players:
            if p != player and not p.folded:
                stats = self.player_stats[p.name]
                opponent_stats[p.name] = {
                    "vpip": stats["vpip"] / max(1, stats["total_hands"]),
                    "pfr": stats["pfr"] / max(1, stats["total_hands"]),
                    "aggression": stats["af"],
                    "recent_actions": p.action_history[-5:] if p.action_history else []
                }
        return opponent_stats

    def get_preflop_aggressors(self):
        """获取翻牌前的激进玩家"""
        aggressors = []
        for player in self.players:
            for round_name, action in player.action_history:
                if round_name == "翻牌前" and action[0] in ['bet', 'raise']:
                    aggressors.append(player)
                    break
        return aggressors

    def get_player_position(self, player):
        """获取玩家位置（0-1，1表示最后位置）"""
        player_index = self.players.index(player)
        active_players = [p for p in self.players if not p.folded and p.chips > 0]
        active_indices = [self.players.index(p) for p in active_players]

        # 计算相对位置
        position_in_active = active_indices.index(player_index)
        return position_in_active / (len(active_indices) - 1) if len(active_indices) > 1 else 0.5

    def evaluate_ai_hand_strength(self, player):
        """评估AI手牌强度（0-1之间）- 增强版"""
        all_cards = player.hand + self.community_cards

        if len(self.community_cards) == 0:
            # 翻牌前手牌强度评估 - 更精确的范围
            rank1, rank2 = player.hand[0].rank.rank_value, player.hand[1].rank.rank_value
            suited = player.hand[0].suit == player.hand[1].suit

            # 对子
            if rank1 == rank2:
                if rank1 >= 13:  # KK+
                    return 0.90 + (rank1 - 13) * 0.05
                elif rank1 >= 11:  # JJ-QQ
                    return 0.75 + (rank1 - 11) * 0.075
                elif rank1 >= 9:  # 99-TT
                    return 0.60 + (rank1 - 9) * 0.075
                elif rank1 >= 7:  # 77-88
                    return 0.50 + (rank1 - 7) * 0.05
                else:  # 22-66
                    return 0.35 + rank1 * 0.025

            # 高张组合
            high_card = max(rank1, rank2)
            low_card = min(rank1, rank2)
            gap = high_card - low_card

            # 更精确的起手牌矩阵
            if high_card == 14:  # Ace
                if low_card >= 13:  # AK
                    return 0.75 if suited else 0.70
                elif low_card >= 12:  # AQ
                    return 0.68 if suited else 0.63
                elif low_card >= 11:  # AJ
                    return 0.62 if suited else 0.57
                elif low_card >= 10:  # AT
                    return 0.58 if suited else 0.53
                else:  # A2-A9
                    base = 0.35 + low_card * 0.02
                    return base + 0.05 if suited else base

            # 百老汇牌（Broadway）
            elif high_card >= 11 and low_card >= 10:
                base = 0.50 + (high_card - 11) * 0.05 + (low_card - 10) * 0.03
                return base + 0.05 if suited else base

            # 同花连张
            elif gap <= 2 and suited:
                return 0.35 + high_card * 0.02 + (3 - gap) * 0.02

            # 其他牌
            else:
                base = 0.15 + high_card * 0.015 + low_card * 0.01
                if suited:
                    base += 0.04
                if gap == 1:
                    base += 0.03
                return min(0.7, max(0.1, base))

        else:
            # 有公共牌时的牌力评估
            hand_rank, values = self.evaluate_hand(all_cards)

            # 更细致的牌型强度映射
            strength_map = {
                HandRank.HIGH_CARD: 0.05,
                HandRank.PAIR: 0.25,
                HandRank.TWO_PAIR: 0.50,
                HandRank.THREE_OF_A_KIND: 0.70,
                HandRank.STRAIGHT: 0.75,
                HandRank.FLUSH: 0.80,
                HandRank.FULL_HOUSE: 0.90,
                HandRank.FOUR_OF_A_KIND: 0.96,
                HandRank.STRAIGHT_FLUSH: 0.98,
                HandRank.ROYAL_FLUSH: 1.0
            }

            base_strength = strength_map.get(hand_rank, 0.05)

            # 根据具体情况调整
            base_strength = self.adjust_hand_strength(hand_rank, values, player.hand, self.community_cards,
                                                      base_strength)

            # 考虑听牌可能性
            draw_strength = self.evaluate_draws(player.hand, self.community_cards)

            # 考虑阻断牌效应
            blocker_value = self.evaluate_blockers(player.hand, self.community_cards)

            final_strength = max(base_strength, draw_strength) + blocker_value

            return min(0.99, max(0.01, final_strength))

    def adjust_hand_strength(self, hand_rank, values, hole_cards, community_cards, base_strength):
        """根据具体情况调整牌力"""
        board_ranks = [c.rank.rank_value for c in community_cards]

        if hand_rank == HandRank.PAIR:
            pair_rank = values[0]
            # 检查对子类型
            if pair_rank in [c.rank.rank_value for c in hole_cards]:
                # 口袋对子
                if pair_rank > max(board_ranks):
                    base_strength += 0.15  # 超对
                elif pair_rank == max(board_ranks):
                    base_strength += 0.10  # 顶对
            else:
                # 公共牌对子
                base_strength -= 0.05

            # 踢脚调整
            kicker = values[1] if len(values) > 1 else 0
            if kicker >= 12:  # Q+踢脚
                base_strength += 0.05

        elif hand_rank == HandRank.TWO_PAIR:
            # 检查是否都是手牌
            if all(v in [c.rank.rank_value for c in hole_cards] for v in values[:2]):
                base_strength += 0.10

        elif hand_rank == HandRank.THREE_OF_A_KIND:
            # 暗三条vs明三条
            trip_rank = values[0]
            hole_ranks = [c.rank.rank_value for c in hole_cards]
            if hole_ranks.count(trip_rank) == 2:
                base_strength += 0.10  # 暗三条更强

        return base_strength

    def evaluate_blockers(self, hole_cards, community_cards):
        """评估阻断牌价值"""
        blocker_value = 0
        all_cards = hole_cards + community_cards

        # 检查同花阻断
        suits = [c.suit for c in all_cards]
        for suit in Suit:
            if suits.count(suit) >= 3:
                # 我们持有该花色的A或K
                for card in hole_cards:
                    if card.suit == suit and card.rank.rank_value >= 13:
                        blocker_value += 0.02

        # 检查顺子阻断
        ranks = sorted([c.rank.rank_value for c in all_cards])
        for i in range(len(ranks) - 3):
            if ranks[i + 3] - ranks[i] <= 4:
                # 我们持有关键顺子牌
                for card in hole_cards:
                    if ranks[i] <= card.rank.rank_value <= ranks[i + 3]:
                        blocker_value += 0.01

        return blocker_value

    def evaluate_draws(self, hand, community):
        """增强的听牌评估"""
        if len(community) >= 5:  # 河牌没有听牌
            return 0

        all_cards = hand + community
        max_draw_strength = 0

        # 同花听牌
        suits = {}
        for card in all_cards:
            suits[card.suit] = suits.get(card.suit, [])
            suits[card.suit].append(card.rank.rank_value)

        for suit, ranks in suits.items():
            if len(ranks) == 4:
                # 坚果同花听牌检查
                if 14 in ranks:  # A高同花听牌
                    draw_strength = 0.40 if len(community) == 3 else 0.35
                else:
                    draw_strength = 0.35 if len(community) == 3 else 0.30
                max_draw_strength = max(max_draw_strength, draw_strength)

        # 顺子听牌
        ranks = sorted([c.rank.rank_value for c in all_cards])
        unique_ranks = sorted(list(set(ranks)))

        # 两头顺子听牌
        for i in range(len(unique_ranks) - 3):
            needed = []
            for r in range(unique_ranks[i], unique_ranks[i] + 5):
                if r not in unique_ranks:
                    needed.append(r)

            if len(needed) == 1:  # 只差一张
                if needed[0] > unique_ranks[i] and needed[0] < unique_ranks[i + 3]:
                    # 卡顺
                    draw_strength = 0.28 if len(community) == 3 else 0.23
                else:
                    # 两头顺
                    draw_strength = 0.35 if len(community) == 3 else 0.30
                max_draw_strength = max(max_draw_strength, draw_strength)

        # 同花顺听牌
        for suit, ranks in suits.items():
            if len(ranks) >= 3:
                sorted_ranks = sorted(ranks)
                for i in range(len(sorted_ranks) - 2):
                    if sorted_ranks[i + 2] - sorted_ranks[i] <= 4:
                        # 可能的同花顺听牌
                        max_draw_strength = max(max_draw_strength, 0.45)

        return max_draw_strength

    def make_bet(self, player, amount):
        """执行下注"""
        actual_bet = amount - player.current_bet
        actual_bet = min(actual_bet, player.chips)

        player.chips -= actual_bet
        player.current_bet = amount
        self.pot += actual_bet

        if amount > self.current_bet:
            self.current_bet = amount

        if player.chips == 0:
            player.all_in = True
            if not self.verbose_mode and player.is_ai:
                self.print_ai_action(player.name, 'allin')

        # 更新统计
        self.update_player_stats(player, 'bet' if self.current_bet == 0 else 'raise')

    def update_player_stats(self, player, action):
        """更新玩家统计数据"""
        stats = self.player_stats[player.name]
        stats["total_hands"] += 1

        # 记录最近的激进度
        if "recent_aggression" not in stats:
            stats["recent_aggression"] = []

        if action in ['bet', 'raise']:
            stats["recent_aggression"].append(1)
        elif action == 'call':
            stats["recent_aggression"].append(0.5)
        else:
            stats["recent_aggression"].append(0)

        # 保持最近10手
        if len(stats["recent_aggression"]) > 10:
            stats["recent_aggression"].pop(0)

    def post_blinds(self):
        """下盲注"""
        # 找到下一个有筹码的玩家作为小盲注
        small_blind_pos = (self.dealer_position + 1) % len(self.players)
        while self.players[small_blind_pos].chips <= 0:
            small_blind_pos = (small_blind_pos + 1) % len(self.players)

        # 找到下一个有筹码的玩家作为大盲注
        big_blind_pos = (small_blind_pos + 1) % len(self.players)
        while self.players[big_blind_pos].chips <= 0:
            big_blind_pos = (big_blind_pos + 1) % len(self.players)

        small_blind_player = self.players[small_blind_pos]
        big_blind_player = self.players[big_blind_pos]

        # 下小盲注
        sb_amount = min(self.small_blind, small_blind_player.chips)
        if sb_amount > 0:
            small_blind_player.chips -= sb_amount
            small_blind_player.current_bet = sb_amount
            self.pot += sb_amount
            print(f"{small_blind_player.name} 下小盲注 {sb_amount}")

        # 下大盲注
        bb_amount = min(self.big_blind, big_blind_player.chips)
        if bb_amount > 0:
            big_blind_player.chips -= bb_amount
            big_blind_player.current_bet = bb_amount
            self.pot += bb_amount
            self.current_bet = bb_amount
            print(f"{big_blind_player.name} 下大盲注 {bb_amount}")

    def showdown(self):
        """摊牌"""
        print("\n=== 摊牌 ===")
        active_players = [p for p in self.players if not p.folded]

        if len(active_players) == 1:
            winner = active_players[0]
            winner.chips += self.pot
            print(f"{winner.name} 获胜，赢得底池 {self.pot}")
            return

        # 评估所有玩家的牌
        player_hands = []
        for player in active_players:
            all_cards = player.hand + self.community_cards
            hand_rank, hand_values = self.evaluate_hand(all_cards)
            player_hands.append((player, hand_rank, hand_values))
            print(f"{player.name}: {player.hand} - {hand_rank.name}")

        # 按牌型和牌值排序
        player_hands.sort(key=lambda x: (x[1].value, x[2]), reverse=True)

        # 找出获胜者
        winners = [player_hands[0]]
        for i in range(1, len(player_hands)):
            if (player_hands[i][1] == winners[0][1] and
                    player_hands[i][2] == winners[0][2]):
                winners.append(player_hands[i])
            else:
                break

        # 分配底池
        win_amount = self.pot // len(winners)
        for winner, _, _ in winners:
            winner.chips += win_amount
            winner.showdown_wins += 1
            print(f"{winner.name} 获胜，赢得 {win_amount}")

        # 记录输家
        for player, _, _ in player_hands:
            if player not in [w[0] for w in winners]:
                player.showdown_losses += 1

    def play_round(self):
        """进行一轮游戏"""
        print("\n" + "=" * 50)
        print(f"新的一轮开始 - 庄家位置: {self.players[self.dealer_position].name}")
        print("=" * 50)

        # 重置
        self.pot = 0
        self.current_bet = 0
        self.community_cards = []
        self.board_texture = {
            "wetness": 0,
            "paired": False,
            "flush_possible": False,
            "straight_possible": False,
            "high_card_board": False
        }

        for player in self.players:
            player.reset_for_new_round()

        # 创建新牌组
        self.create_deck()

        # 下盲注
        self.post_blinds()

        # 发底牌
        self.deal_cards()

        # 翻牌前下注
        self.betting_round("翻牌前")

        if len([p for p in self.players if not p.folded]) <= 1:
            self.showdown()
            return

        # 翻牌
        self.deal_community_cards(3)
        print(f"\n翻牌: {self.community_cards}")
        self.betting_round("翻牌")

        if len([p for p in self.players if not p.folded]) <= 1:
            self.showdown()
            return

        # 转牌
        self.deal_community_cards(1)
        print(f"\n转牌: {self.community_cards}")
        self.betting_round("转牌")

        if len([p for p in self.players if not p.folded]) <= 1:
            self.showdown()
            return

        # 河牌
        self.deal_community_cards(1)
        print(f"\n河牌: {self.community_cards}")
        self.betting_round("河牌")

        # 摊牌
        self.showdown()

        # 移动庄家位置到下一个有筹码的玩家
        self.dealer_position = (self.dealer_position + 1) % len(self.players)
        while self.players[self.dealer_position].chips <= 0:
            self.dealer_position = (self.dealer_position + 1) % len(self.players)

    def display_chip_counts(self):
        """显示所有玩家筹码"""
        print("\n当前筹码情况:")
        for player in self.players:
            status = " (已淘汰)" if player.chips <= 0 else ""
            win_rate = ""
            if player.showdown_wins + player.showdown_losses > 0:
                wr = player.showdown_wins / (player.showdown_wins + player.showdown_losses) * 100
                win_rate = f" | 摊牌胜率: {wr:.1f}%"
            print(f"{player.name}: {player.chips}{status}{win_rate}")

    def play_game(self):
        """开始游戏"""
        print("欢迎来到德州扑克 - 挑战增强版！")
        print("\n你将对战5个不同风格的强力AI玩家")
        print(f"\n起始筹码: 1000")
        print(f"小盲注/大盲注: {self.small_blind}/{self.big_blind}")

        round_num = 0
        while True:
            # 检查是否还有玩家有筹码
            active_players = [p for p in self.players if p.chips > 0]
            if len(active_players) <= 1:
                if active_players[0] == self.players[0]:
                    print("\n恭喜你赢得了游戏！你击败了所有AI对手！")
                else:
                    print(f"\n游戏结束，{active_players[0].name}获胜！")
                break

            if self.players[0].chips <= 0:
                print("\n你已经输光了所有筹码，游戏结束！")
                print("这些AI对手确实很有挑战性，再接再厉！")
                break

            round_num += 1
            print(f"\n第 {round_num} 轮")

            self.play_round()
            self.display_chip_counts()

            # 自动继续，除非游戏结束


# 运行游戏
if __name__ == "__main__":
    game = TexasHoldem()
    game.play_game()